import { RegisterComponent } from '@feng3d/ecs';
import { EventEmitter } from '@feng3d/event';
import { Component3D, Node3DEventMap, PerspectiveCamera3D } from 'feng3d-three';
import { Event, Object3D } from 'three';
import { TransformControls } from '../thirdparty/three/imports';

declare module '@feng3d/ecs'
{
    interface ComponentMap { TransformControls3D: TransformControls3D; }

}

export interface TransformControls3DEventMap extends Node3DEventMap
{
    mouseDown: any;
    mouseUp: any;
    change: any;
    objectChange: any;
    'dragging-changed': any;
}

export interface TransformControls3D
{
    readonly emitter: EventEmitter<TransformControls3DEventMap>;
}

/**
 * 3D透视摄像机，包装`three`中`TransformControls`。
 */
@RegisterComponent({ name: 'TransformControls3D' })
export class TransformControls3D extends Component3D
{
    _controls: TransformControls;

    camera: PerspectiveCamera3D;

    domElement: HTMLElement;

    get size()
    {
        return this._controls.size;
    }
    set size(v)
    {
        this._controls.size = v;
    }

    get showX()
    {
        return this._controls.showX;
    }
    set showX(v)
    {
        this._controls.showX = v;
    }

    get space()
    {
        return this._controls.space;
    }
    set space(v)
    {
        this._controls.space = v;
    }

    get object()
    {
        return this._controls.object;
    }
    set object(v)
    {
        this._controls.object = v;
    }

    init()
    {
        super.init();

        this._controls = new TransformControls(this.camera._camera, this.domElement);
        this.entity._group.add(this._controls);

        this._controls.addEventListener('mouseDown', this._onEventHandler);
        this._controls.addEventListener('mouseUp', this._onEventHandler);
        this._controls.addEventListener('change', this._onEventHandler);
        this._controls.addEventListener('objectChange', this._onEventHandler);
        this._controls.addEventListener('dragging-changed', this._onDraggingChanged);
    }

    destroy(): void
    {
        this.entity._group.remove(this._controls);
        this._controls.removeEventListener('mouseDown', this._onEventHandler);
        this._controls.removeEventListener('mouseUp', this._onEventHandler);
        this._controls.removeEventListener('change', this._onEventHandler);
        this._controls.removeEventListener('objectChange', this._onEventHandler);
        this._controls.removeEventListener('dragging-changed', this._onDraggingChanged);

        this._controls = null;

        super.destroy();
    }

    private _onEventHandler = (e: Event) =>
    {
        this.emitter.emit(e.type as any, {});
    };

    private _onDraggingChanged = (e: Event) =>
    {
        this.emitter.emit(e.type as any, e);
    };

    /**
     * @todo
     *
     * @param object
     */
    attach(object: Object3D<Event>)
    {
        this._controls.attach(object);
    }

    detach()
    {
        this._controls.detach();

        return this;
    }
}
